package vip.wangwenhao.sso.config.security.handler;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.data.redis.SessionOperation;
import org.springframework.stereotype.Component;
import vip.wangwenhao.common.util.RedisUtils;
import vip.wangwenhao.mq.api.dto.Message;
import vip.wangwenhao.mq.api.enums.MessageTypeEnum;
import vip.wangwenhao.autoconfigure.pojo.UserDetailsPojo;
import vip.wangwenhao.common.enums.RedisKeysEnum;
import vip.wangwenhao.common.enums.RoleEnum;
import vip.wangwenhao.common.util.CookieUtils;
import vip.wangwenhao.common.util.ServiceUtils;
import vip.wangwenhao.mq.api.rpcservice.WebsocketRpcService;
import vip.wangwenhao.sso.service.TokenService;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;

/**
 * @author wwh
 * @date 2019年12月30日 16:53
 */

@Slf4j
@Component
public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    @Autowired
    private RedisOperationsSessionRepository redisOperationsSessionRepository;
    @Autowired
    private SessionOperation sessionOperation;
    @Autowired
    private WebsocketRpcService websocketRpcService;
    @Autowired
    private TokenService tokenService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

        Object principal = authentication.getPrincipal();
        String uid = CookieUtils.getRequestCookieInfo(request);
        request.getSession().setAttribute("uid", uid);

        if (null != principal && principal instanceof UserDetailsPojo) {
            Long userId = ((UserDetailsPojo) principal).getId();
            String username = ((UserDetailsPojo) principal).getUsername();

            log.info("{} login success", username);

            String sessionRedisKey = RedisKeysEnum.GLOBAL_PRESENT_ORDER_TIME.getKey() + userId;
            Collection<GrantedAuthority> authorities = ((UserDetailsPojo) principal).getAuthorities();
            boolean isAdmin = authorities.stream().anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(RoleEnum.admin.name()));
            String sessionId = request.getSession().getId();
            Object redisSessionId = RedisUtils.hGet(sessionRedisKey, "sessionId");
            if (null != redisSessionId) {
                String otherSessionId = String.valueOf(redisSessionId);
                Object redisUid = RedisUtils.hGet(sessionRedisKey, "uid");

                //非管理员单设备登录
                if (StringUtils.isNotBlank(otherSessionId) && !sessionId.equals(otherSessionId) && !isAdmin) {
                    //同步会话信息
                    sessionOperation.loginSuccess(sessionId, otherSessionId);
                    log.warn("用户 {} 强退！", username);
                    redisOperationsSessionRepository.deleteById(otherSessionId);

                    if (null != redisUid) {
                        Message message = Message.builder()
                                .uid(String.valueOf(redisUid))
                                .code(MessageTypeEnum.USER_OTHER_DEVICE_LOGIN.getCode())
                                .content("有其他设备登录该账号，若是可信操作请忽略，否则请修改密码")
                                .build();
//                        websocketRpcService.sendToUser(message,accessToken.getValue());
//                        HttpUtils.post("http://localhost:8095/mq/ws/user", message, Result.class);
                        ServiceUtils.service("service-mq", "/mq/ws/user", message, Message.class);
                    }
                }
            }

            RedisUtils.hPut(sessionRedisKey, "sessionId", sessionId);
            RedisUtils.hPut(sessionRedisKey, "uid", uid);
        } else {
            log.info("{} logout success", principal);
        }


        super.onAuthenticationSuccess(request, response, authentication);
    }
}